home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / sgi2fax / imgtofax.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  10KB  |  378 lines

  1. /*    $Header: /usr/people/sam/fax/sgi2fax/RCS/imgtofax.c,v 1.15 1994/02/28 14:23:09 sam Rel $
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. /*
  26.  * Prepare SGI image files for transmission as facsimile.
  27.  * Each image is scaled to fit a standard page, sharpened
  28.  * with a hipass filter, gamma warp'd, and then dithered
  29.  * to a bilevel image.
  30.  *
  31.  * Output is a single TIFF Class F file with each image as
  32.  * a separate page/directory.
  33.  *
  34.  * Derived from Paul Haeberli's imgtofax program.
  35.  */
  36. #include <stdio.h>
  37. #include <math.h>
  38. #include <image.h>
  39. #include "hipass.h"
  40. #include "izoom.h"
  41. #include "lut.h"
  42. #include "lum.h"
  43. #include "tiffio.h"
  44. #include <stdarg.h>
  45. #include "PageSize.h"
  46.  
  47. #define GAMMAVAL        0.8
  48.  
  49. #define    DEF_MARGIN    14
  50. #define    DEF_TOPMARGIN    0
  51. #define    DEF_BOTMARGIN    0
  52.  
  53. static    short sbuf[4096];
  54. static    IMAGE* iimage;
  55. static    highpass *hp;
  56. static    zoom* zm;
  57. static    TIFF* tif;
  58. static    lut* lookup;
  59. static    int npages;
  60.  
  61. static    int pixelWidth;
  62. static    int pixelHeight;
  63. static    int leftMargin        = DEF_MARGIN;
  64. static    int rightMargin        = DEF_MARGIN;
  65. static    int topMargin        = DEF_TOPMARGIN;
  66. static    int bottomMargin    = DEF_BOTMARGIN;
  67. static    int pageWidth;
  68. static    int pageHeight;
  69. static    float pageres    = 196.;        /* default is medium res */
  70. static    long g3opts    = GROUP3OPT_FILLBITS;
  71.  
  72. static void
  73. fatal(char* va_alist, ...)
  74. #define    fmt va_alist
  75. {
  76.     va_list ap;
  77.     va_start(ap, fmt);
  78.     fprintf(stderr, "sgi2fax: ");
  79.     vfprintf(stderr, fmt, ap);
  80.     fprintf(stderr, ".\n");
  81.     va_end(ap);
  82.     exit(-1);
  83. }
  84. #undef fmt
  85.  
  86. static void
  87. getimgrow(buf,y)
  88. short *buf;
  89. int y;
  90. {
  91.     getbwrow(iimage,buf,iimage->ysize-1-y);
  92. }
  93.  
  94. static void
  95. getzrow(buf,y)
  96. short *buf;
  97. int y;
  98. {
  99.     getzoomrow(zm,buf,y);
  100. }
  101.  
  102. static void
  103. tofax(short* wp, int n)
  104. {
  105. #define MAXXSIZE    2432
  106.     char row[(MAXXSIZE+7) &~ 7], *rp = row;
  107.     int bit = 0x80;
  108.  
  109.     memset(row, 0, sizeof (row));
  110.     while (n-- > 0) {
  111.     if (*wp++ < 128)
  112.         *rp |= bit;
  113.     if ((bit >>= 1) == 0) {
  114.         rp++;
  115.         bit = 0x80;
  116.     }
  117.     }
  118.     (void) TIFFWriteScanline(tif, row,
  119.     TIFFCurrentRow(tif) == -1 ? 0 : TIFFCurrentRow(tif), 0);
  120. }
  121.  
  122. static float transfunc(f)
  123. float f;
  124. {
  125.     return pow(f,GAMMAVAL);
  126. }
  127.  
  128. /* 
  129.  *      dithering stuff follows
  130.  *
  131.  */
  132. #define MATSIZE88
  133.  
  134. #define XSIZE   8
  135. #define YSIZE   8
  136.  
  137. static short Xdithmat[YSIZE][XSIZE] = {         /* 8x8 floyd-steinberg */
  138.         0,      8,      36,     44,     2,      10,     38,     46,
  139.         16,     24,     52,     60,     18,     26,     54,     62,
  140.         32,     40,     4,      12,     34,     42,     6,      14,
  141.         48,     56,     20,     28,     50,     58,     22,     30,
  142.         3,      11,     39,     47,     1,      9,      37,     45,
  143.         19,     27,     55,     63,     17,     25,     53,     61,
  144.         35,     43,     7,      15,     33,     41,     5,      13,
  145.         51,     59,     23,     31,     49,     57,     21,     29,
  146. };
  147.  
  148. static short dithmat[YSIZE][XSIZE] = {          /* halftone dots */
  149.         3,      17,     55,     63,     61,     47,     9,      1,
  150.         15,     29,     39,     51,     49,     35,     25,     13,
  151.         40,     32,     26,     20,     22,     30,     36,     42,
  152.         56,     44,     10,     4,      6,      18,     52,     58,
  153.         60,     46,     8,      0,      2,      16,     54,     62,
  154.         48,     34,     24,     12,     14,     28,     38,     50,
  155.         23,     31,     37,     43,     41,     33,     27,     21,
  156.         7,      19,     53,     59,     57,     45,     11,     5,
  157. };
  158.  
  159. #define TOTAL           (XSIZE*YSIZE)
  160.  
  161. static ditherrow(buf,y,n)
  162. short *buf;
  163. int y, n;
  164. {
  165.     int r, val;
  166.     int rshades, rmaxbits;
  167.     short *rdith, *gdith, *bdith;
  168.  
  169.     rdith = &dithmat[y%YSIZE][0];
  170.     rshades = TOTAL+1;
  171.     rmaxbits = ((rshades-1)/TOTAL);
  172.     while(n--) {
  173.         r = *buf;
  174.         val = (rshades*r)/255;
  175.         if(val>=TOTAL) 
  176.             *buf++ = 255;
  177.         else if(val>rdith[n%XSIZE])
  178.             *buf++ = 255;
  179.         else
  180.             *buf++ = 0;
  181.     }
  182. }
  183.  
  184. static void
  185. blankSpace(int nrows)
  186. {
  187.     setrow(sbuf,255,pixelWidth);
  188.     while (nrows-- > 0)
  189.         tofax(sbuf,pixelWidth);
  190. }
  191.  
  192. static void
  193. imgtofax(char* input, int pn)
  194. {
  195.     int ixsize, iysize;
  196.     int oxsize, oysize;
  197.     int ymargin;
  198.     int i, y;
  199.  
  200.     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (long) pixelWidth);
  201.     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (long) pixelHeight);
  202.     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, -1L);
  203.     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
  204.     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
  205.     TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  206.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
  207.     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
  208.     TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
  209.     TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
  210.     TIFFSetField(tif, TIFFTAG_XRESOLUTION, 204.);
  211.     TIFFSetField(tif, TIFFTAG_YRESOLUTION, pageres);
  212.     TIFFSetField(tif, TIFFTAG_PAGENUMBER, pn, npages);
  213.     TIFFSetField(tif, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN);
  214.     { char buf[1024];
  215.       sprintf(buf, "Ditherered B&W version of %s", input);
  216.       TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, buf);
  217.     }
  218.     TIFFSetField(tif, TIFFTAG_SOFTWARE, "sgi2fax");
  219.     TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
  220.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS, g3opts);
  221.  
  222. /* calculate the zoom factor */
  223.     ixsize = iimage->xsize;
  224.     iysize = iimage->ysize;
  225.     oxsize = pageWidth;
  226.     oysize = (iysize*pageWidth)/ixsize;        /* maintain aspect ratio */
  227.     if (pageres == 98.)
  228.     oysize /= 2;
  229.  
  230. /* set up the filters */
  231.     zm = newzoom(getimgrow, ixsize, iysize, oxsize, oysize, TRIANGLE, 1.0);
  232.     hp = newhp(getzrow, oxsize, oysize, 2.0);
  233.  
  234.     ymargin = (pageHeight-oysize)/2;
  235.     if(ymargin<0)
  236.         ymargin = 0;
  237.     blankSpace(topMargin + ymargin);
  238.     for(y=0; y<oysize; y++) {
  239.         hpgetrow(hp, sbuf, y); 
  240.         applylut(lookup, sbuf, oxsize);
  241.         ditherrow(sbuf, y, oxsize);
  242.         tofax(sbuf, pixelWidth);
  243.     }
  244.     blankSpace(bottomMargin + ymargin);
  245.  
  246.     freezoom(zm);
  247.     freehp(hp);
  248.  
  249.     TIFFWriteDirectory(tif);
  250. }
  251.  
  252. static void
  253. usage()
  254. {
  255.     fprintf(stderr, "usage: sgi2fax %s %s %s %s %s %s %s [-12] file ...\n",
  256.     "[-h height]",
  257.     "[-w width]",
  258.     "[-v vres]",
  259.     "[-o output]",
  260.     "[-r %red]",
  261.     "[-g %green]",
  262.     "[-b %blue]",
  263.     ""
  264.     );
  265.     exit(-1);
  266. }
  267.  
  268. #define    CVT(x)    (((x)*255)/100)
  269.  
  270. main(argc, argv)
  271.     int argc;
  272.     char **argv;
  273. {
  274.     extern int optind;
  275.     extern char* optarg;
  276.     char* output = "sgi.fax";
  277.     int c;
  278.     float w, h;
  279.     struct pageSizeInfo* info;
  280.  
  281.     info = getPageSize("default");
  282.     w = getPageWidth(info);
  283.     h = getPageHeight(info);
  284.     delPageSize(info);
  285.     while ((c = getopt(argc, argv, "o:r:g:b:h:s:v:w:12")) != -1)
  286.     switch (c) {
  287.     case '1':
  288.         g3opts &= ~GROUP3OPT_2DENCODING;
  289.         break;
  290.     case '2':
  291.         g3opts |= GROUP3OPT_2DENCODING;
  292.         break;
  293.     case 'r':            /* %red illumination */
  294.         _RILUM = CVT(atoi(optarg));
  295.         break;
  296.     case 'g':            /* %green illumination */
  297.         _GILUM = CVT(atoi(optarg));
  298.         break;
  299.     case 'b':            /* %blue illumination */
  300.         _BILUM = CVT(atoi(optarg));
  301.         break;
  302.     case 'o':            /* output file */
  303.         output = optarg;
  304.         break;
  305.     case 's':            /* page size */
  306.         info = getPageSize(optarg);
  307.         if (!info) {
  308.         fprintf(stderr, "%s: Unknown page size \"%s\".\n",
  309.             argv[0], optarg);
  310.         exit(-1);
  311.         }
  312.         w = getPageWidth(info);
  313.         h = getPageHeight(info);
  314.         delPageSize(info);
  315.         break;
  316.     case 'v':            /* vertical resolution (lines/inch) */
  317.         pageres = atof(optarg);
  318.         /* XXX force acceptable resolutions */
  319.         if (pageres < 120.)
  320.         pageres = 98.;
  321.         else
  322.         pageres = 196.;
  323.         break;
  324.     case 'w':            /* page width (mm) */
  325.         w = atof(optarg);
  326.         break;
  327.     case 'h':            /* page height (mm) */
  328.         h = atof(optarg);
  329.         break;
  330.     case '?':
  331.         usage();
  332.     }
  333.     if (argc - optind < 1)
  334.     usage();
  335.  
  336.     /* XXX force known sizes */
  337.     if (w > 280)
  338.     pixelWidth = 2432;
  339.     else if (w > 230)
  340.     pixelWidth = 2048;
  341.     else
  342.     pixelWidth = 1728;
  343.     if (h > 350)
  344.     pixelHeight = 2810;
  345.     else if (h > 280)
  346.     pixelHeight = 2292;
  347.     else
  348.     pixelHeight = 2166;
  349.  
  350.     if (pageres == 98.) {
  351.     pixelHeight /= 2;
  352.     topMargin /= 2;
  353.     bottomMargin /= 2;
  354.     }
  355.     pageWidth = pixelWidth - (leftMargin + rightMargin);
  356.     pageHeight = pixelHeight - (topMargin + bottomMargin);
  357.  
  358. /* open the output file */
  359.     tif = TIFFOpen(output, "w");
  360.     if (!tif)
  361.     fatal("%s: Can not create output file", output);
  362.  
  363.     lookup = makelut(transfunc,256,256,0);
  364.  
  365.     npages = argc - optind;
  366.     for (c = 0; optind < argc; c++, optind++) {
  367.     iimage = iopen(argv[optind], "r");
  368.     if (!iimage) {
  369.         fprintf(stderr, "sgi2fax: %s: Can not open\n", argv[optind]);
  370.         continue;
  371.     }
  372.     imgtofax(argv[optind], c);
  373.     }
  374.     TIFFClose(tif);
  375.     freelut(lookup);
  376.     exit(0);
  377. }
  378.